package CCN::modules::core_boostrap::_database_model;
# Copyright (C) 2006  Stephane Alnet
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
# 

#
# For more information visit http://carrierclass.net/
#
use strict; use warnings;

use base qw(CCN::Core::Database);

use CCN::Text;

# --- Tools ---

sub my_mac()
{
    return CCN::Core::Type::mac::clean(CCN::Core::Configuration::get('my-mac'));
}

# --- Class initialization ---

sub _init
{
    my $self = shift;
    # First open the database we use to provision ourselves.
    $self->SUPER::_init(@_);

    # --- Identify which server we are running on

    #   Find the MAC address used at registration time.
    $self->{mac} = $self->my_mac();

    #   Obtain system name and server name from the MAC.
    $self->die('No system identification found.')
        unless defined $self->{mac};

    my ($system_name,$system_pk,$system_manager,$server_pk,$operating_system,
        $db_member,
        $dns_master, $ntp_master
       ) = $self->sql_get( <<'SQL', $self->{mac} );
            SELECT systems.dns_name, systems.id, systems.manager, server.id, server.operating_system,
                    server.db_member,
                    server.dns_master, server.ntp_master
            FROM server, systems
            WHERE server.the_system = systems.id
                AND server.id = (SELECT server FROM server_interface WHERE mac = ?)
SQL

    # This should never happen, except for the manager, in which case we'd be in trouble. :)
    $self->die('This server is not configurable (no server).')
        unless defined $server_pk   and $server_pk   ne '';
    $self->die('This server is not configurable (no system).')
        unless defined $system_name and $system_name ne '';
    $self->die('This server is not configurable (no operating system).')
        unless defined $operating_system and $operating_system ne '';

    $self->{system_pk}          = $system_pk;
    $self->{system_name}        = $system_name;
    $self->{system_manager}     = $system_manager;
    $self->{server_pk}          = $server_pk;
    $self->{server_name}        = $self->make_server_name($server_pk);
    $self->{operating_system}   = $operating_system;

    # Initialize clusters information

    $self->{db_member}          = $db_member;
    $self->{db_cluster}         = $self->make_cluster_name($db_member,'db')
        if defined $db_member;
        
    $self->{dns_master} = $dns_master =~ /^t/i;
    $self->{ntp_master} = $ntp_master =~ /^t/i;

}

sub system_pk()         { return shift->{system_pk}; }
sub system_name()       { return shift->{system_name}; }
sub server_pk()         { return shift->{server_pk}; }
sub server_name()       { return shift->{server_name}; }
sub operating_system    { return shift->{operating_system}; }

# PRECONDITION: server_pk has the same the_system as this server.
sub make_server_name($)
{
    my $self = shift;
    my $server_pk = shift;
    return 's'.$server_pk.'.server.'.$self$self->p->system_name;
}

# PRECONDITION: cluster_pk has the same the_system as this server.
sub make_cluster_name($$)
{
    my $self = shift;
    my $cluster_pk = shift;
    my $cluster_type = shift;
    $self->die("No cluster_pk") if not defined $cluster_pk;
    $self->die("No cluster_type") if not defined $cluster_type;
    return 'c'.$cluster_pk.'.'.$cluster_type.'.'.$self$self->p->system_name;
}

sub is_a_gui_node()
{
    my $self = shift;
    $self->{is_a_gui_node} =  $self->sql_get( <<'SQL', $self->server_pk ) > 0
        SELECT COUNT(*) FROM provisioning_servers WHERE server = ?
SQL
        unless exists $self->{is_a_gui_node};
    return $self->{is_a_gui_node};
}

sub is_a_cdn_upstream_node()
{
    my $self = shift;
    $self->{is_a_cdn_upstream_node} = $self->sql_get( <<'SQL', $self->server_pk ) > 0
        SELECT COUNT(*) FROM server WHERE cdn_upstream_server = ?
SQL
        unless exists $self->{is_a_cdn_upstream_node};
    return $self->{is_a_cdn_upstream_node};
}

sub is_a_cdn_downstream_node()
{
    my $self = shift;
    $self->{is_a_cdn_downstream_node} = $self->sql_get( <<'SQL', $self->server_pk ) > 0
        SELECT COUNT(*) FROM server WHERE cdn_downstream_server = ?
SQL
        unless exists $self->{is_a_cdn_downstream_node};
    return $self->{is_a_cdn_downstream_node};
}

sub is_manager()
{
    my $self = shift;
    return defined $self->{system_manager} && $self->server_pk == $self->{system_manager};
}

sub manager() {
    my $self = shift;
    $self->{manager} = $self->get( "system", "manager", {id => $self->system_pk} )
        unless exists $self->{manager};
    return $self->{manager};
}

sub force_manager() {
    return defined CCN::Configuration::get('force_manager');
}

sub primary_db_server()
{
    my $self = shift;
    return undef if not defined $self->{db_member};
    return $self->sql_get( <<'SQL' ,$self->{db_member});
        SELECT MIN(id) FROM server WHERE db_member = ?
SQL
}

# get_db_names returns undef/() if we are not the primary for the targetted db.
# By default get_db_names() provide information for the GUI database (IFF it is local).
sub get_db_names()
{
    return shift->get_provisioning_db_names();
}

sub get_provisioning_db_names()
{
    my $self = shift;

    return unless defined $self->{db_member} and $self->system_pk == $self->primary_db_server;

    my @db_names =
        $self->sql_get_array(q(SELECT db_name FROM provisioning WHERE db_cluster = ?),
            $self->{db_member});

    return @db_names;
    # If no record was found it means we are not the proper db_cluster.
}

1;
